﻿using System;
using Tesla.Bounding;
using Tesla.Core;
using Tesla.Graphics;
using Tesla.Math;
using Tesla.Scene;
using Tesla.Scene.Shape;

namespace TeslaSamples.Renderer {
        [AppDescription("Many Lights Sample", PlatformCapabilities.Direct3D10 | PlatformCapabilities.XNA4, "ManyLightsImage", "ManyLightsDesc", "ManyLightsSource")]
    public class ManyLightsSample : BasicApp {
        private Random random = new Random();

        protected override void LoadContent() {
            Window.Title = "Many Lights Sample";
            ClearColor = Color.Black;

            Node lightNode = new Node("LightNode");
            lightNode.SceneHints.LightCombineHint = LightCombineHint.Off;
            for(int i = 0; i < 30; i++) {
                CreateRandomLight(i, lightNode);
            }

            RootNode.AddChild(lightNode);

            for(int i = 0; i < 60; i++) {
                CreateRandomSphere(i, RootNode);
            }

            RootNode.SetModelBound(new BoundingBox());
        }

        protected override void OnUpdate(GameTime time) {
            RootNode.SortLights();
        }

        private void CreateRandomLight(int id, Node parent) {
            Color diffuse = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());

            Sphere lightSphere = new Sphere("LightSphere " + id.ToString(), 5, 5, .5f);
            lightSphere.SceneHints.LightCombineHint = LightCombineHint.Off;
            lightSphere.SetSolidColor(diffuse);
            lightSphere.Material = ContentManager.Load<Material>("BasicVertColor.tem");


            PointLight pl = new PointLight();
            pl.Attenuate = true;
            pl.Constant =.1f;
            pl.Linear = .001f;
            pl.Quadratic = 0.001f;
            pl.IsEnabled = true;
            pl.Diffuse = diffuse;
            pl.Ambient = Color.Black;// new Color(.1f, .1f, .1f);

            RootNode.AddLight(pl);

            lightSphere.AddController(new LightSpatialController(pl, random));
            parent.AddChild(lightSphere);
        }

        private void CreateRandomSphere(int id, Node parent) {
            Sphere sphere = new Sphere("Sphere " + id.ToString(), 18, 18, (float)random.NextDouble() * 1.75f + 1.25f);
            sphere.Translation = new Vector3((float) random.NextDouble() * 120 - 40,
                (float) random.NextDouble() * 120 - 40,
                (float) random.NextDouble() * 120 - 40);
            sphere.SetSolidColor(Color.DarkGray);
            sphere.Lights.MaxLights = 4;
            sphere.Lights.GlobalAmbient = Color.Black;
            sphere.Material = ContentManager.Load<Material>("LitBasicVertColor.tem").Clone();
            parent.AddChild(sphere);
        }
    }

    class LightSpatialController : ISpatialController {
        private bool _isEnabled;
        private PointLight _light;
        private Vector3 _time;
        private float _speed;

        public bool IsEnabled {
            get {
                return _isEnabled;
            }
            set {
                _isEnabled = value;
            }
        }

        public LightSpatialController(PointLight light, Random random) {
            _light = light;
            _isEnabled = true;

            _time = new Vector3((float) random.NextDouble() * MathHelper.Pi * 8, 
                (float) random.NextDouble() * MathHelper.Pi * 8, 
                (float) random.NextDouble() * MathHelper.Pi * 8);
            _speed = (float) random.NextDouble();
        }

        public void Update(GameTime time, Spatial caller) {
            _time.X += (float) time.ElapsedTimeInSeconds * _speed;
            _time.Y += (float) time.ElapsedTimeInSeconds * _speed;
            _time.Z += (float) time.ElapsedTimeInSeconds * _speed;

            Vector3 pos;
            pos.X = (float) System.Math.Sin(_time.X * .4f) * 80;
            pos.Y = (float) System.Math.Cos(_time.Y * .5f) * 80;
            pos.Z = (float) System.Math.Sin(_time.Z * .6f) * 80;

            _light.Position = pos;
            caller.Translation = pos;
        }
    }
}
